/**
 * arall-plus
 *
 * npm 安装
 * npm i --save ar-call-sdk
 */
import ARTCCalling from "ar-call-sdk";

// 配置信息
import Config from "./config";
// 信息提示
import Message from "./message";

import store from "@/store";

// 实例
let callClient = null;

/**
 * 判断当前项目是否存在实例，不存在将无法使用
 * @returns
 */
export const refreshBash = () => {
  return callClient;
};

/**
 * 初始化
 */
export const initCallClient = () => {
  if (callClient) return;
  console.log("初始化");
  // 初始化实例
  callClient = new ARTCCalling({
    appId: Config.CONFIG_APPID,
    rtcConfig: Config.CONFIG_RTCCONFIG ? Config.CONFIG_RTCCONFIG : null,
    rtmConfig: Config.CONFIG_RTMCONFIG ? Config.CONFIG_RTMCONFIG : null,
  });

  //  SDK 版本
  console.log("SDK 版本", callClient.getSdkVersion());

  // 初始化回调
  // 音频检测(频道内说活人员)
  callClient.on(ARTCCalling.EVENT.USER_VOLUME, (result) => {
    store.commit("addVolumePrompt", result);
    // result.forEach((volume, index) => {
    //   // console.log(`${index} UID ${volume.uid} Level ${volume.level}`);
    // });
  });
  // 网络状态
  callClient.on(
    ARTCCalling.EVENT.CONNECTION_STATE_CHANGED,
    (status, reason) => {
      console.log("网络状态", status, reason);
    }
  );
  // 用户加入
  callClient.on(ARTCCalling.EVENT.USER_ENTER, (userInfo) => {
    store.commit("joinMultiRemoteInfoList", userInfo.peer);
    console.log("用户加入", userInfo);
  });
  // 用户离开
  callClient.on(ARTCCalling.EVENT.USER_LEFT, (userInfo) => {
    console.log("用户离开 USER_LEFT", userInfo);
    Message({ message: "用户" + userInfo.peer.userId + "离开", type: "error" });
    // 多人场景下使用
    store.commit("deleteMultiRemoteInfo", userInfo.peer);
  });
  // 重复登录
  callClient.on(ARTCCalling.EVENT.KICK_OUT, () => {
    console.log("重复登录 EVENT.KICK_OUT");
    Message({ message: "账号异地登录", type: "error" });
    alert("账号异地登录");
  });
  // 用户发布
  callClient.on(
    ARTCCalling.EVENT.USER_PUBLISH,
    async (callDetail, user, mediaType) => {
      if (mediaType === "video") {
        Message({ message: "用户：" + user.uid + "视频开启" });
        // 远端视图渲染
        // 判断当前大屏的uid是否与用户一致
        const localLargeScreen = store.getters.getCurrentLargeScreen.userId;
        if (localLargeScreen === user.uid) {
          // 渲染到大屏(大流)
          await startView(
            {
              userId: user.uid,
              viewDomId: "view_windows_large",
              lowStream: false,
            },
            "远端视图"
          );
        } else {
          // 渲染到小屏(小流)
          await startView(
            {
              userId: user.uid,
              viewDomId: "view_windows_small" + user.uid,
              lowStream: true,
            },
            "远端视图"
          );
        }
      }
      if (mediaType === "audio") {
        Message({ message: "用户：" + user.uid + "音频开启" });
      }

      // 通话类型
      const getModel = store.getters.getModel;
      if (getModel === 0) {
        store.commit("optionMultiRemoteInfoList", {
          userId: user.uid,
          hasAudio: user.hasAudio,
          hasVideo: user.hasVideo,
          loading: false, // 关闭加载
        });
      } else {
        store.commit("optionP2PMultiRemoteInfo", {
          userId: user.uid,
          hasAudio: user.hasAudio,
          hasVideo: user.hasVideo,
          loading: false, // 关闭加载
        });
      }

      // 判断当前用户是否跟大屏用户一致，一致则更新信息
      const currentLargeScreen = store.getters.getCurrentLargeScreen;
      if (currentLargeScreen.userId === user.uid) {
        store.commit("updataCurrentLargeScreen", {
          userId: user.uid,
          hasAudio: user.hasAudio,
          hasVideo: user.hasVideo,
        });
      }
    }
  );
  // 用户取消发布
  callClient.on(
    ARTCCalling.EVENT.USER_UNPUBLISH,
    (callDetail, user, mediaType) => {
      if (mediaType === "video") {
        Message({ message: "用户：" + user.uid + "视频关闭" });
      }
      if (mediaType === "audio") {
        Message({ message: "用户：" + user.uid + "音频关闭" });
      }

      // 通话类型
      const getModel = store.getters.getModel;
      if (getModel === 0) {
        store.commit("optionMultiRemoteInfoList", {
          userId: user.uid,
          hasAudio: user.hasAudio,
          hasVideo: user.hasVideo,
          loading: false, // 关闭加载
        });
      } else {
        store.commit("optionP2PMultiRemoteInfo", {
          userId: user.uid,
          hasAudio: user.hasAudio,
          hasVideo: user.hasVideo,
          loading: false, // 关闭加载
        });
      }

      // 判断当前用户是否跟大屏用户一致，一致则更新信息
      const currentLargeScreen = store.getters.getCurrentLargeScreen;
      if (currentLargeScreen.userId === user.uid) {
        store.commit("updataCurrentLargeScreen", {
          userId: user.uid,
          hasAudio: user.hasAudio,
          hasVideo: user.hasVideo,
        });
      }
    }
  );
  // 视频通话转音频通话(p2p使用)
  callClient.on(ARTCCalling.EVENT.SWITCH_TO_AUDIO_CALL, () => {
    console.log("视频通话转音频通话 EVENT.SWITCH_TO_AUDIO_CALL");
    // 停止本地预览
    callClient?.stopLocalView();
    // 返回
    store.commit("updataPattern", "audio");
  });
  // 通话结束
  callClient.on(ARTCCalling.EVENT.END_CALL, (reason) => {
    console.log("通话结束 EVENT.END_CALL", reason);
    Message({ message: "通话结束" });
    // 停止本地预览
    callClient?.stopLocalView();
    // 清空状态
    store.commit("statusClearAll", true);
    // 返回
    store.commit("updataCommentsStatus", 0);
  });

  // 通话结束(主叫有用,远端用户不在线)
  callClient.on(
    ARTCCalling.EVENT.PUSH_OFFLINE_MESSAGE,
    async (offlineUsers) => {
      // 用户信息
      console.log("通话结束(远端用户不在线)", offlineUsers);

      if (store.getters.getModel == 1) {
        // 点对点模式下挂断
        await hangup();
        Message({
          message: "远端用户不在线",
          type: "error",
        });
        // // 清空状态
        // store.commit("statusClearAll", true);
        // // 返回
        // store.commit("updataCommentsStatus", 0);
      }
    }
  );

  // 收到远程发起的呼叫邀请
  callClient.on(
    ARTCCalling.EVENT.INVITED,
    async (calleeUserInfo, calleeUserList) => {
      // 发起者相关信息
      console.log("发起者相关信息", calleeUserInfo, calleeUserList);
      // 记录当前用户为被叫
      store.commit("updataIsCallingParty", false);
      // 收到的情景类型
      store.commit(
        "updataPattern",
        calleeUserInfo.mode == 1 ? "audio" : "video"
      );
      // 情景模式
      store.commit("updataModel", calleeUserInfo.multi ? 0 : 1);

      if (calleeUserInfo.multi) {
        // 远端主叫信息 + 主叫呼叫其他用户信息列表(包含本身)
        store.commit("addMultiRemoteInfoList", [
          calleeUserInfo.peer,
          ...calleeUserList,
        ]);
      } else {
        // p2p
        // 存入远端用户信息
        store.commit("addP2PRemoteInfo", calleeUserInfo.peer);
      }
      store.commit("updataCommentsStatus", 1);
    }
  );
  // 远程接收呼叫邀请
  callClient.on(ARTCCalling.EVENT.ACCEPT_CALL, (calleeUserInfo) => {
    console.log("远程接收呼叫邀请 EVENT.ACCEPT_CALL", calleeUserInfo);

    // 开启音频检测(发起呼叫时或接收到呼叫时调用)
    // callClient?.enableAudioVolumeIndicator();
    // 判断 p2p 相关逻辑
    if (!calleeUserInfo.multi) {
      // 存入远端用户信息
      store.commit("addP2PRemoteInfo", calleeUserInfo.peer);
      // 通话模式
      store.commit(
        "updataPattern",
        calleeUserInfo.mode == 1 ? "audio" : "video"
      );
      store.commit("updataCommentsStatus", 2);
    }
    // 开始计时
    store.commit("controlCallTime", true);
  });
  // 远程拒绝呼叫邀请
  callClient.on(
    ARTCCalling.EVENT.REJECT_CALL,
    (calleeUserInfo, refuseReason) => {
      console.log(
        "远程拒绝呼叫邀请 EVENT.REJECT_CALL",
        calleeUserInfo,
        refuseReason
      );
      if (calleeUserInfo.multi) {
        // 多人通话模式下
        store.commit("deleteMultiRemoteInfo", calleeUserInfo.peer);
      } else {
        // 点对点通话模式下返回首页
        store.commit("updataCommentsStatus", 0);
        // 清空状态
        store.commit("statusClearAll", true);
      }
      Message({
        message: "用户:" + calleeUserInfo.peer.userId + "拒绝呼叫邀请",
        type: "error",
      });
    }
  );
  // 远程无应答（呼叫邀请）
  callClient.on(ARTCCalling.EVENT.NO_RESPONSE, (calleeUserInfo) => {
    console.log("远程无应答（呼叫邀请） EVENT.NO_RESPONSE", calleeUserInfo);
    if (calleeUserInfo.multi) {
      // 多人通话模式下
      store.commit("deleteMultiRemoteInfo", calleeUserInfo.peer);
    } else {
      // 点对点通话模式下返回上一级
      // 清空状态
      store.commit("statusClearAll", true);
      store.commit("updataCommentsStatus", 0);
    }
    Message({
      message: "用户:" + calleeUserInfo.peer.userId + "无应答",
      type: "error",
    });
  });
  // 远程正在通话中，忙线中（拒绝呼叫邀请）
  callClient.on(ARTCCalling.EVENT.LINE_BUSY, (calleeUserInfo) => {
    console.log("远程正在通话中，忙线中 EVENT.LINE_BUSY", calleeUserInfo);
    Message({
      message: `用户：${calleeUserInfo.peer.userId}正在通话中，忙线中`,
      type: "error",
    });
    // 获取情景模式
    const oModel = store.getters.getModel;
    if (oModel == 0) {
      // 多人通话模式下
      store.commit("deleteMultiRemoteInfo", calleeUserInfo.peer);
      // 无人情况下
      if (store.state.multiRemoteInfoList.length === 0) {
        // 主动挂断
        rejectCall();
      }
      console.log("state.multiRemoteInfoList");
    } else {
      rejectCall();
      store.commit("statusClearAll", true);

      // 返回首页
      store.commit("updataCommentsStatus", 0);
    }
  });

  // 主叫取消呼叫邀请
  callClient.on(ARTCCalling.EVENT.CANCEL_CALL, (callerUserInfo) => {
    Message({ message: "主叫取消呼叫邀请" });
    store.commit("statusClearAll", true);
    console.log("主叫取消呼叫邀请 EVENT.CANCEL_CALL", callerUserInfo);
    // 返回首页
    store.commit("updataCommentsStatus", 0);
  });
  // 呼叫邀请已过期，未及时应答（呼叫邀请）
  callClient.on(ARTCCalling.EVENT.CALLING_TIMEOUT, (callerUserInfo) => {
    Message({ message: "邀请已过期，未及时应答", type: "error" });
    store.commit("statusClearAll", true);
    // 作为被邀请方会收到，收到该回调说明本次通话超时未应答
    console.log(
      "呼叫邀请已过期，未及时应答（呼叫邀请） EVENT.CALLING_TIMEOUT",
      callerUserInfo
    );
    // 返回首页
    store.commit("updataCommentsStatus", 0);
  });
};

/**
 * 登录 arcall-plus 系统
 * @param userInfo 登录用户信息
 */
export const loginArcallPlus = (userInfo) => {
  return callClient.login(userInfo);
};

/**
 * 发起 p2p 呼叫
 * @param userInfo 呼叫用户信息
 * @param callType 呼叫用户类型 0:视频童虎 1:语音通话
 */
export const makeP2PCall = (userInfo, callType) => {
  console.log("发起 p2p 呼叫用户信息", userInfo, callType);
  console.log("callClient", callClient);
  // 发起呼叫
  return new Promise((resolve, reject) => {
    callClient
      .call({
        user: userInfo,
        // 通话类型
        mode: callType,
      })
      .then(() => {
        resolve();
      })
      .catch((err) => {
        console.log("呼叫失败", err);
        // sdk 错误
        if (err.name === "ARCallingException") {
          switch (err.code) {
            case 1:
              Message({ message: "对方不在线，无法呼叫", type: "error" });
              hangup();
              break;
            case 100:
              Message({ message: "没有音频设备", type: "warning" });
              break;
            case 101:
              Message({ message: "没有视频设备", type: "warning" });
              break;
            case 102:
              Message({ message: "没有设备", type: "warning" });
              break;
            default:
              break;
          }
        }

        reject(err);
      });
  });
};

/**
 * 发起多人呼叫
 */
export const makeMultiCall = (userInfo, callMode) => {
  console.log("发起多人呼叫", userInfo, callMode);

  // 发起呼叫
  return new Promise((resolve, reject) => {
    callClient
      .groupCall({
        type: 0,
        users: userInfo,
        // 通话类型
        mode: callMode,
        // // 自定义离线消息推送
        // offlinePushInfo: CallOfflinePushInfo
      })
      .then(() => {
        resolve();
      })
      .catch((err) => {
        console.log("呼叫失败", err);
        // sdk 错误
        if (err.name === "ARCallingException") {
          switch (err.code) {
            case 1:
              Message({ message: "对方不在线，无法呼叫", type: "error" });
              hangup();
              break;
            case 100:
              Message({ message: "没有音频设备", type: "warning" });
              break;
            case 101:
              Message({ message: "没有视频设备", type: "warning" });
              break;
            case 102:
              Message({ message: "无音频设备，无视频设备", type: "warning" });
              break;
            default:
              break;
          }
        }
        reject(err);
      });
  });
};

/**
 * 取消邀请/取消通话(通用)
 */
export const hangup = async () => {
  await callClient.hangup();
  // 清空状态
  store.commit("statusClearAll", true);
  // 返回原页面
  store.commit("updataCommentsStatus", 0);
};

/**
 * 接受通话邀请(通用)
 */
export const acceptCall = async () => {
  await callClient.accept();
  // 开启音频检测(发起呼叫时或接收到呼叫时调用)
  // await callClient?.enableAudioVolumeIndicator();
  // 开始计时
  store.commit("controlCallTime", true);
};

/**
 * 拒绝通话邀请(通用)
 */
export const rejectCall = () => {
  callClient.reject();
  // 返回原页面
  store.commit("updataCommentsStatus", 0);
};

/**
 * 将视频通话切换语音通话
 * 仅支持1v1通话过程中使用
 */
export const switchToAudioCall = () => {
  return callClient.switchToAudioCall();
};

/**
 * 显示视图(通用)
 */
export const startView = async (viewInfo, type = "本地视图") => {
  if (type === "本地视图") {
    await callClient.startLocalView({
      viewDomId: viewInfo.viewDomId,
    });
  }
  if (type === "远端视图") {
    await callClient.startRemoteView({
      userId: viewInfo.userId,
      viewDomId: viewInfo.viewDomId,
      fit: "contain",
      // 大小流 true为小流
      lowStream: viewInfo.lowStream,
    });
  }
};
/**
 * 停止预览
 */
export const stopView = (type = "本地视图", userId) => {
  console.log("停止预览", userId);
  if (type === "本地视图") {
    return callClient.stopLocalView();
  }
  if (type === "远端视图") {
    return callClient.stopRemoteView({ userId: userId || "" });
  }
};
/**
 * 设置麦克风禁音(通用) boolean
 * setMicMute
 */
export const setMicMute = (control) => {
  return callClient.setMicMute(control);
};

/**
 * 打开/关闭摄像头 boolean
 * setCameraMute (通用)
 */
export const setCameraMute = (control) => {
  return callClient.setCameraMute(control);
};
